package com.ll19.framework.spring.support;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;

/**
 * 用来获取spring的applicationContext ,在非注入程序中
 * 
 * @author <a href="http://www.LL19.com/">LL19.com</a>
 */
public class ContextUtils {

	private static ApplicationContext applicationContext;

	private static Log log = LogFactory.getLog(ContextUtils.class);

	public static void setApplicationContext(
			ApplicationContext applicationContext) {
		/**
		 * 同步方法
		 * 
		 */
		synchronized (ContextUtils.class) {
			log.debug("setApplicationContext, notifyAll");
			ContextUtils.applicationContext = applicationContext;

			// notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。两者的最大区别在于：

			// notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态，变成等待该对象上的锁，一旦该对象被解锁，他们就会去竞争。

			// notify
			// 则文明得多他只是选择一个wait状态线程进行通知，并使它获得该对象上的锁，但不惊动其他同样在等待被该对象notify的线程们，当第一个线程运行完
			// 毕以后释放对象上的锁此时如果该对象没有再次使用notify语句，则即便该对象已经空闲，其他wait状态等待的线程由于没有得到该对象的通知，继续处
			// 在wait状态，直到这个对象发出一个notify或notifyAll，它们等待的是被notify或notifyAll，而不是锁。

			ContextUtils.class.notifyAll();
		}
	}

	public static ApplicationContext getApplicationContext() {
		synchronized (ContextUtils.class) {
			while (applicationContext == null) {
				try {
					log.debug("getApplicationContext, wait...");
					ContextUtils.class.wait(60000);
					if (applicationContext == null) {
						log.warn(
								"Have been waiting for ApplicationContext to be set for 1 minute",
								new Exception());
					}
				} catch (InterruptedException ex) {
					log.debug("getApplicationContext, wait interrupted");
				}
			}
			return applicationContext;
		}
	}

	public static Object getBean(String name) {

		/**
		 * 
		 * getApplicationContext用同步锁 效率有问题
		 * 
		 */
		return getApplicationContext().getBean(name);
	}

}